/*************************************************************************
*File Name: isocket.cpp
*Author: 侯广臣
*2801059691@qq.com
*Created Time: Mon 18 Jan 2021 03:34:16 PM CST
 ************************************************************************/
#include "isocket.h"


//backlog:监听队列长度
C_ListenSocket::C_ListenSocket(int backlog, const char *ip, int port)
{
    Init(backlog, ip, port);
}

//初始化套接字m_m_sockfd，如果m_sockfd不为-1那么关闭它，错误返回-1，正确返回套接字
int C_ListenSocket::Init(int backlog, const char *ip, int port)
{
    if(backlog <= 0 || port < 0)
    {
        #ifdef IDEBUG
            PrintErrorInfo("Init() 参数错误");
        #endif
        return -1;
    }
    //系统分配套接字，AF_INET：协议簇为网络套接字，SOCK_STREAM：数据流协议，TCP协议
    m_sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(m_sockfd == -1)
    {
        #ifdef IDEBUG
            PrintStdErrorInfo("socket()");
        #endif
        return -1;
    }
    //设置套接字端口复用
    int opt = 1;
    setsockopt(m_sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(opt));
    //服务器地址结构体
    struct sockaddr_in serverAddr;
    //初始化结构体所有字节为 0
    memset(&serverAddr, 0, sizeof(serverAddr));
    //绑定协议簇为网络套接字
    serverAddr.sin_family = AF_INET;
    //htons:把整数端口号转换为网络字节序地址
    serverAddr.sin_port = htons(port);
    if(ip == nullptr)
    {//监听所有本地地址
        serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    }
    else
    {//inet_addr:把字符串地址转换为网络字节序地址
        serverAddr.sin_addr.s_addr = inet_addr(ip);
    }

    //绑定服务器地址
    if(bind(m_sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1)
    {
        #ifdef IDEBUG
            PrintStdErrorInfo("bind()");
        #endif
        close(m_sockfd);
        return -1;
    }
    //设置监听状态
    if(listen(m_sockfd, backlog) == -1)
    {
        #ifdef IDEBUG
            PrintStdErrorInfo("listen()");
        #endif
    }

    return m_sockfd;
}

//返回已经连接的客户端套接字
int C_ListenSocket::Accept(void)
{
    return accept(m_sockfd, (struct sockaddr*)&m_clientAddr, &m_clientAddrLength);
}

//向字符串buf中写入当前连接客户端的信息IP地址，port端口信息。成功返回buf指针，失败nullptr
char* C_ListenSocket::GetClientInfo(char buffer[], int bufferLen)
{
    if(m_sockfd == -1)
    {
        return nullptr;
    }

    if(inet_ntop(AF_INET, (void*)&m_clientAddr.sin_addr, buffer, bufferLen) == nullptr)
    {
        #ifdef IDEBUG
            PrintStdErrorInfo("inet_ntop()");
        #endif
        return nullptr;
    }
    int len = strlen(buffer);
    char *temp = buffer + len;
    if(sprintf(temp, ":%d", ntohs(m_clientAddr.sin_port)) <= 0)
    {
        return nullptr;
    }

    return buffer;
}
